#!/bin/sh
#Barry Kauler www.puppylinux.com
#LGPL 2007 Puppy Linux www.puppylinux.com
#some usb adaptors have slots for cards, plugging/unplugging these cards
#does not cause a hotplug event and the kernel does not update /proc.
#120602 kernel 3.2.18 major deviance from earlier kernels, /proc/partitions (and /sys/block) now shows /dev/sr0 when no disk.
#       new situation, getting duplicate /dev/sr0 so need 'sort -u'.

if [ -f /etc/rc.d/functions_x ] ; then
	. /etc/rc.d/functions_x
fi

usage() {
	echo "probepart - show information about partitions

Syntax:

   probepart [options] [device]

It will print info about all the valid partitions

Output: DEVICE|FILESYSTEM|SIZE

Example: /dev/sda1|ext4|827465877
   SIZE = 512 byte blocks [default]

Options:

   -extra-info: show DEVICE|FILESYSTEM|SIZE|LABEL|MOUNT_STATUS
   -no-optical: ignore optical devices
   -m         : SIZE in MB
   -k         : SIZE in KB
   -hr        : human readable SIZE
   zz...      : a way to easily identify the current
                probepart process through 'ps'..
                ex: zzFRONTEND_CHANGE

[device]
   it's possible to specify wildcards
      ex: probepart 'sda.*'      (probe sda drive and partitions)
      ex: probepart 'sdb[0-9]'   (probe sdb partitions 0-9)
      ex: probepart 'sdc[0-9].*' (probe all sdc partitions)
"
	exit
}

PROCESS_OPTICAL=yes #default

for i in $@ ; do
	case $1 in
		-k|-m) SUNITS="$1" ; shift ;; #allowed params are '-k' or '-m'.
		-hr|-hr-size) HR_SIZE=yes ; shift ;;
		-extra-info) EXTRA_INFO=yes ; shift ;; #/dev/$ONEDEV|$FSTYPE|$SIZE|$LABEL
		-no-optical) PROCESS_OPTICAL=no ; shift ;;
		-h|-help|--help) usage ;;
		zz*)  shift ;;
	esac
done

device="${1##*/}"
 

if [ "$device" ] ; then
	# process cli argument
	ALLDEVS="`grep " ${device}$" /proc/partitions | tr -s ' ' | cut -f 4-5 -d ' '`"
	## this is faster but requires changes in scripts using wildcards .. and bash 4.4?
	#ALLDEVS=$(
	#	while read zz zzz size dev ; do
	#		case $dev in $device)
	#			echo $size $dev ;;
	#		esac
	#	done < /proc/partitions
	#)
	if [ ! "$ALLDEVS" ] ; then
		echo "${device}: invalid device" 1>&2
		exit 1
	fi
	ONEDEV_ARG=1
else
	#normal operation
	if [ -f $HOME/.usb-drive-log-probepart ] ; then #force /proc upate mechanism
		while read ONEUSBDRV ; do
			dd if=/dev/$ONEUSBDRV of=/dev/null bs=512 count=1 &>/dev/null
		done < $HOME/.usb-drive-log-probepart
	fi
	#devices that have partitions... 
	#130127 screen out sr0-sr9. early kernels do not have these in /proc/partitions, 3.2+ do, which causes desktop icon to not appear when audio-cd inserted.
	# size|partition
	PARTITIONS="`cat /proc/partitions | tr -s ' ' | cut -f 4-5 -d ' ' | grep -vE ' loop| ram| zram| sr |dm-'`" #each line ex: 16076800 sda5
	## this is faster but requires changes in scripts using wildcards .. and bash 4.4?
	#PARTITIONS=$(
	#	while read zz zzz size dev ; do
	#		case $dev in loop*|ram*|zram*|sr*)
	#			continue ;; #not allowed
	#		esac
	#		echo $size $dev
	#	done < /proc/partitions
	#)
	if [ "$PROCESS_OPTICAL" = "yes" ] ; then
		#plus optical devices...
		# size|drv
		OPTICALDRVS=$(
		for dev in /sys/block/sr*
		do
			[ -e $dev ] || continue
			dev=${dev##*/}
			read -r size < /sys/block/${dev}/size
			size=$(($size/2)) # kb = /proc/partitions
			echo ${size} ${dev}
		done
		)
	fi
	ALLDEVS="$(echo -e "${PARTITIONS}\n${OPTICALDRVS}" | sort -k 2,2 -u)"
fi

#==========================================================================

while read SIZE ONEDEV
do

	[ -z "$SIZE" -o -z "$ONEDEV" ] && continue

	if [ -e /dev/${ONEDEV} ] ; then
		blockdev=/dev/${ONEDEV}
	elif [ -e /dev/block/${ONEDEV} ] ; then
		blockdev=/dev/block/${ONEDEV} #android
	else
		continue
	fi

	OPTICAL="no"
	if fx_drv_is_optical ${ONEDEV} ; then
		OPTICAL="yes"
		[ "$PROCESS_OPTICAL" = "no" ] && continue
	fi

	case $ONEDEV in fd*)
		[ ! -e /sys/block/${ONEDEV}/device/vendor -a ! -e /sys/block/${ONEDEV}/device/model ] && continue ;;
	esac

	if [ "$OPTICAL" = "yes" ];then
		while read dev etc ; do
			if [ "$dev" = "$blockdev" ] ; then #mounted
				#...returns 0 if disc inserted, else 255. #very fast.
				cddetect_quick -d${blockdev} >/dev/null 2>&1 || continue
				break
			fi
		done < /proc/mounts
	fi

	BLKDID_OUT="$(busybox blkid ${blockdev} 2>/dev/null)"
	FSTYPE=""
	case $BLKDID_OUT in *' TYPE="'*)
		FSTYPE="${BLKDID_OUT##* TYPE=\"}"
		FSTYPE="${FSTYPE%%\"*}" ;;
	esac

	if [ "$FSTYPE" = "" ] ; then
		[ $SIZE -le 4 ] && continue #extended partition (most likely)
		FSTYPE="unknown"
	fi

	if [ "$FSTYPE" = "unknown" -a "$OPTICAL" = "yes" ];then # probe optical a bit more.
		cddetect -q -d${blockdev} > /dev/null 2>&1
		case $? in 
			1) FSTYPE="audiocd" ;;
			*) FSTYPE=`guess_fstype ${blockdev}` ;;
		esac
	fi

	if [ "$EXTRA_INFO" = "yes" ] ; then
		PARTITION_LABEL=""
		case $BLKDID_OUT in *' LABEL="'*)
			PARTITION_LABEL="${BLKDID_OUT##* LABEL=\"}"
			PARTITION_LABEL="${PARTITION_LABEL%%\"*}" ;;
		esac
		MOUNT_STATUS="not_mounted"
		while read dev etc ; do
			[ "$dev" = "$blockdev" ] && MOUNT_STATUS="mounted" && break
		done < /proc/mounts
		EXTRA_STUFF="|${PARTITION_LABEL}|${MOUNT_STATUS}"
	fi

	if [ "$FSTYPE" = "unknown" ] ; then
		if [ "$ONEDEV_ARG" != "1" -a "$OPTICAL" != "yes" -a -e /sys/block/${ONEDEV} ] ; then
			# drive with no f.s.. ignore
			continue
		fi
		FSTYPE="none"
	fi

	if [ "$HR_SIZE" = "yes" ] ; then
		SIZE=$(fx_format_bytes $(($SIZE * 1024)) ) #format size in KB
	else
		case $SUNITS in
			-m) SIZE=$(($SIZE/1024)) ;; #want MB
			-k) true                 ;; #want KB
			"") SIZE=$(($SIZE*2))    ;; #want 512 byte blocks.
		esac
	fi

	echo "${blockdev}|$FSTYPE|$SIZE${EXTRA_STUFF}"

	[ "$ONEDEV_ARG"  ] && continue #(finished processing cli argument)

	#keep record of usb devs, for forced updating of /proc...
	if [ -e /sys/block/${ONEDEV} ] ; then
		case $(readlink /sys/block/${ONEDEV}) in *usb*)
			echo "${DEVDRV}" >> $HOME/.usb-drive-log-probepart
			sorted="$(sort -u $HOME/.usb-drive-log-probepart)"
			echo "$sorted" > $HOME/.usb-drive-log-probepart ;;
		esac
	fi

done <<EOF
$ALLDEVS
EOF

### END ###
